home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 21
/
Mac Magazin and MacEasy Magazine CD - Issue 21.iso
/
Wissenschaft & Technik
/
yorick12vr1-nofpu folder
/
startup
/
zbuf.i
< prev
Wrap
Text File
|
1996-02-08
|
26KB
|
890 lines
/*
ZBUF.I
Yorick interface to z-buffered graphics. Uses same interface
as Munro's plwf, but scales coords to fit into the z-buffer
range.
$Id: zbuf.i,v 1.1 1994/11/10 23:13:12 langer Exp $
*/
/* Copyright (c) 1994. The Regents of the University of California.
All rights reserved. */
/*
require, "plwf.i";
*/
extern zbuf_terp, pixbuf_terp;
extern nx_zbuf_terp, ny_zbuf_terp;
extern x_viewpoint, y_viewpoint, z_viewpoint;
extern trans_vec1, trans_vec2, trans_vec3;
extern fixed_map, no_project, use_viewpoint;
extern view_box, view_world, view_dist;
use_viewpoint= 1;
no_project= 1;
x_viewpoint= y_viewpoint= z_viewpoint= 0.0;
view_box= array(0.0, 2, 2);
/* ------------------------------------------------------------------------ */
func draw_tri(x, y, z, colr)
/* DOCUMENT draw_tri(x, y, z, colr)
draws the triangle with corners at (x,y,z) where the three
variables are all vectors of length 3. colr may be either a scalar
color index for the whole triangle or a length 3 vector for the
three corners. Draws into the z-buffer which is later strobed
to the screen. The points are transformed using the current
projection.
SEE ALSO: show_zbuf, set_proj;
*/
{
if(numberof(x) != 3 || numberof(y) != 3 || numberof(z) != 3) {
error,"coordinate array is not length three in draw_tri";
}
if(numberof(colr) != 1 && numberof(colr) != 3) {
error,"color must be of length 1 or 3 in draw_tri";
}
/* transform from world coords to viewpoint coords */
do_trans, x, y, z;
/* project the x and y coords */
project, x, y, z;
pick_viewbox, x, y;
map_to_scrn, x, y;
/* don't take a chance on the type of colr */
colr= char(colr);
if(numberof(colr) == 1) {
tri_draw_1c, x, y, z, colr;
} else {
tri_draw, x, y, z, colr;
}
show_zbuf;
}
func draw_quad_strip(x, y, z, colr)
/* DOCUMENT draw_quad_strip(x, y, z, colr)
draws the strip of quads with corners at (x,y,z).
Dimensions for x,y,z are n by 2.
One quad (two triangles) is drawn for each group of four points, so
there are n-1 quads (2*(n-1) triangles). colr is a list
of color indices and may be either length n-1 to specify an
index for each quad or length n by 2 to specify an
index for each vertex, in which case the color of each point
is interpolated from the surrounding 3 vertices.
Draws into the z-buffer which is later strobed
to the screen. The points are transformed using the current
projection.
SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_list, draw_tri_strip;
*/
{
dimsx= dimsof(x);
dimsy= dimsof(y);
dimsz= dimsof(z);
dimsc= dimsof(colr);
if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
error,"x,y,z arrays do not have same shape in draw_quad_strip";
}
if(dimsx(1) != 2) {
error,"coordinate arrays must be two dimensional in draw_quad_strip";
}
if(dimsx(3) != 2) {
error,"coordinate arrays must be n by 2 in draw_quad_strip";
}
num= dimsx(2);
if(dimsc(1) == 1) {
if(dimsc(2) != num-1) {
error,"color array must be n-1 vector or n by 2 in draw_quad_strip";
}
/* one color per triangle */
one_colr= 1;
} else if(anyof(dimsx != dimsc)) {
error,"color array must be n-1 vector or n by 2 in draw_quad_strip";
} else {
/* one color index per vertex */
one_colr= 0;
}
/* transform from world coords to viewpoint coords */
do_trans, x, y, z;
/* project the x and y coords */
project, x, y, z;
pick_viewbox, x, y;
map_to_scrn, x, y;
/* don't take a chance on the type of colr */
colr= char(colr);
if(one_colr) {
quad_strip_1c, numberof(x(,1)), x(,1), x(,2), y(,1), y(,2), z(,1), z(,2), colr;
} else {
quad_strip, numberof(x(,1)), x(,1), x(,2), y(,1), y(,2), z(,1), z(,2), colr(,1), colr(,2);
}
show_zbuf;
}
func draw_tri_strip(x, y, z, colr)
/* DOCUMENT draw_tri_strip(x, y, z, colr)
draws the strip of triangles with corners at (x,y,z).
One triangle is drawn for each group of three points, so
there are n-2 triangles if there are n points. colr is a list
of color indices and may be either length n-2 to specify an
index for each triangle or length n to specify an
index for each vertex, in which case the color of each point
in a triangle is interpolated from the vertices.
Draws into the z-buffer which is later strobed
to the screen. The points are transformed using the current
projection.
SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_list;
*/
{
dimsx= dimsof(x);
dimsy= dimsof(y);
dimsz= dimsof(z);
dimsc= dimsof(colr);
if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
error,"x,y,z arrays do not have same shape in draw_tri_strip";
}
if(dimsx(1) != 1) {
error,"coordinate arrays must be one dimensional in draw_tri_strip";
}
if(dimsc(1) != 1) {
error,"color array must be one dimensional in draw_tri_strip";
}
if(dimsc(2) == dimsx(2)) {
/* one color index per vertex */
one_colr= 0;
} else if(dimsc(2) == dimsx(2)-2) {
/* one color index per triangle */
one_colr= 1;
} else {
error,"number of colors must equal number of vertices or two less for draw_tri_strip";
}
/* transform from world coords to viewpoint coords */
do_trans, x, y, z;
/* project the x and y coords */
project, x, y, z;
pick_viewbox, x, y;
map_to_scrn, x, y;
num= dimsx(2);
/* don't take a chance on the type of colr */
colr= char(colr);
if(one_colr) {
tri_strip_1c, num, x, y, z, colr;
} else {
tri_strip, num, x, y, z, colr;
}
show_zbuf;
}
func draw_tri_list(x, y, z, colr)
/* DOCUMENT draw_tri_list(x, y, z, colr)
x,y,z have dimensions 3 by n. This function draws the
triangles with corners at (x(,j),y(,j),z(,j)).
colr is a list of color indices and may be either n to specify an
index for each triangle or size 3 by n to specify an
index for each vertex, in which case the color of each point
in a triangle is interpolated from the vertices.
Draws into the z-buffer which is later strobed
to the screen. The points are transformed using the current
projection.
SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_strip;
*/
{
dimsx= dimsof(x);
dimsy= dimsof(y);
dimsz= dimsof(z);
dimsc= dimsof(colr);
if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
error,"x,y,z arrays do not have same shape in draw_tri_list";
}
if(dimsx(1) != 2) {
error,"coordinate arrays must be two dimensional in draw_tri_list";
}
if(dimsx(2) != 3) {
error,"coordinate arrays must have length 3 for first index in draw_tri_list";
}
if(dimsc(1) == 1) {
/* should be one index per triangle */
if(dimsc(2) != dimsx(3)) {
error,"color array must be one per triangle or one per vertex in draw_tri_list";
}
one_colr= 1;
} else if(dimsc(2) != 2) {
error,"color array must be one or two dimensional in draw_tri_list";
} else if(dimsc(3) != dimsx(3)) {
error,"color array must be one per triangle or one per vertex in draw_tri_list";
} else {
one_colr= 0;
}
/* transform from world coords to viewpoint coords */
do_trans, x, y, z;
/* project the x and y coords */
project, x, y, z;
pick_viewbox, x, y;
map_to_scrn, x, y;
num= dimsx(3);
/* don't take a chance on the type of colr */
colr= char(colr);
if(one_colr) {
for(i= 1; i <= num; i++) {
tri_draw_1c, x(,i), y(,i), z(,i), colr(i);
}
} else {
for(i= 1; i <= num; i++) {
tri_draw, x(,i), y(,i), z(,i), colr(,i);
}
}
show_zbuf;
}
func draw_poly_list( npolys, x, y, z, colr)
/* DOCUMENT draw_poly_list( npolys, x, y, z, colr)
x, y, z are lists of vertex coordinates. npolys is an array
with the number of vertices per polygon. colr is the color index
for each polygon and has the same length as npolys.
x,y,z have length equal to sum(npolys). This function draws the
polygons with corners at (x(ilo),y(ilo),z(ilo)) through ihi,
where ilo and ihi are determined from a psum of npolys.
Draws into the z-buffer which is later strobed
to the screen. The points are transformed using the current
projection.
SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_list;
*/
{
num= numberof(npolys);
pspans= npolys(psum);
dimsx= dimsof(x);
dimsy= dimsof(y);
dimsz= dimsof(z);
dimsc= dimsof(colr);
if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
error,"x,y,z arrays do not have same shape in draw_poly_list";
}
if(dimsx(1) != 1) {
error,"coordinate arrays must be one dimensional in draw_poly_list";
}
if(dimsc(1) == 1) {
/* should be one index per triangle */
if(dimsc(2) != num) {
error,"must have one color per polygon in draw_poly_list";
}
} else {
error,"color array must be one dimensional in draw_poly_list";
}
/* transform from world coords to viewpoint coords */
do_trans, x, y, z;
/* project the x and y coords */
project, x, y, z;
pick_viewbox, x, y;
map_to_scrn, x, y;
/* don't take a chance on the type of colr */
colr= char(colr);
ilo= 1;
for(j= 1; j <= num; j++) {
ihi= pspans(j);
nvert= npolys(j);
// write,format="j=%d, nvert=%d\n",j,nvert;
/* handle special cases of a triangle and a quad */
if(nvert == 3) {
tri_draw_1c, x(ilo:ihi), y(ilo:ihi), z(ilo:ihi), colr(j);
// write,format="triangle(c=%d): (%f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n",
// colr(j),x(ilo),y(ilo),z(ilo),x(ilo+1),y(ilo+1),z(ilo+1),x(ihi),y(ihi),z(ihi);
} else if(nvert == 4) {
tri_draw_1c, x(ilo:ihi-1), y(ilo:ihi-1), z(ilo:ihi-1), colr(j);
xx= [x(ilo), x(ilo+2), x(ihi)];
yy= [y(ilo), y(ilo+2), y(ihi)];
zz= [z(ilo), z(ilo+2), z(ihi)];
tri_draw_1c, xx, yy, zz, colr(j);
// write,format="triangle(c=%d): (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n",
// colr(j),x(ilo),y(ilo),z(ilo),x(ilo+1),y(ilo+1),z(ilo+1),x(ilo+2),y(ilo+2),z(ilo+2);
// write,format="triangle(c=%d): (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n",
// colr(j),xx(1),yy(1),zz(1),xx(2),yy(2),zz(2),xx(3),yy(3),zz(3);
} else {
/* tesselate the polygon into a series of triangles.
Assume, FOR NOW!!!, that the triangle is convex.
This means that the average of the vertex coords lies
inside the polygon and can be used as a common point
for all the tesellation triangles. */
xx= yy= zz= array(0.0, 3);
xx(3)= x(ilo:ihi)(avg);
yy(3)= y(ilo:ihi)(avg);
zz(3)= z(ilo:ihi)(avg);
for(k= ilo; k <= ihi-1; k++) {
xx(1:2)= x(k:k+1);
yy(1:2)= y(k:k+1);
zz(1:2)= z(k:k+1);
tri_draw_1c, xx, yy, zz, colr(j);
// write,format="triangle(c=%d): (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n",
// colr(j),xx(1),yy(1),zz(1),xx(2),yy(2),zz(2),xx(3),yy(3),zz(3);
}
xx(1)= x(ilo);
yy(1)= y(ilo);
zz(1)= z(ilo);
xx(2)= x(ihi);
yy(2)= y(ihi);
zz(2)= z(ihi);
tri_draw_1c, xx, yy, zz, colr(j);
// write,format="triangle(c=%d): (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n",
// colr(j),xx(1),yy(1),zz(1),xx(2),yy(2),zz(2),xx(3),yy(3),zz(3);
}
ilo= ihi+1;
}
show_zbuf;
}
struct link3d {
long is_quad, one_colr;
char *colr;
double *data_x, *data_y, *data_z;
double *rot_x, *rot_y, *rot_z;
double *adj_z;
double *proj_x, *proj_y;
double *map_x, *map_y;
link3d *next;
link3d *prev;
}
func add_link3d(x, y, z, colr)
/* DOCUMENT add_link3d(x, y, z, colr)
1) draws the strip of triangles with corners at (x,y,z)
if x, y, and z are 1D arrays.
One triangle is drawn for each group of three points, so
there are n-2 triangles if there are n points. colr is a list
of color indices.
If colr has the same length as x, y, z, there is a color
for each vertex and the colors are interpolated linearly
between vertices. If colr has length 2 less than x, y, and z,
there is a single color for each triangle.
2) draws the strip of quads with corners at (x,y,z)
if the dimensions for x,y,z are n by 2.
One quad (two triangles) is drawn for each group of four points,
so there are n-1 quads (2*(n-1) triangles). colr is a list
of color indices and may be either length n-1 to specify an
index for each quad or length n by 2 to specify an
index for each vertex, in which case the color of each point
is interpolated from the surrounding 3 vertices.
SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_list;
*/
{
dimsx= dimsof(x);
dimsy= dimsof(y);
dimsz= dimsof(z);
dimsc= dimsof(colr);
if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
error,"x,y,z arrays do not have same shape in add_link3d";
}
if(dimsx(1) < 1 || dimsx(1) > 2) {
error,"coordinate arrays must be one or two two dimensional in add_link3d";
}
if(dimsx(1) == 1) {
/* triangle strip */
is_quad= 0;
if(dimsc(1) != 1) {
error,"color array must be one dimensional for triangle strip in add_link3d";
}
if(dimsc(2) == dimsx(2)) {
/* one color index per vertex */
one_colr= 0;
} else if(dimsc(2) == dimsx(2)-2) {
/* one color index per triangle */
one_colr= 1;
} else {
error,"number of colors must equal number of vertices or two less for add_link3d";
}
} else {
/* quad strip */
is_quad= 1;
if(dimsx(3) != 2) {
error,"coordinate arrays must be n by 2 for quad strip in add_link3d";
}
num= dimsx(2);
if(dimsc(1) == 1) {
if(dimsc(2) != num-1) {
error,"color array must be n-1 vector or n by 2 for quad strip in add_link3d";
}
/* one color per triangle */
one_colr= 1;
} else if(anyof(dimsx != dimsc)) {
error,"color array must be n-1 vector or n by 2 for quad strip in add_link3d";
} else {
/* one color index per vertex */
one_colr= 0;
}
}
link= array(link3d);
link.next= list3d_head.next;
if(link.next) (link.next)->prev= &link;
link.prev= &list3d_head;
list3d_head.next= &link;
link.data_x= &x;
link.data_y= &y;
link.data_z= &z;
link.colr= &colr;
link.one_colr= one_colr;
link.is_quad= is_quad;
link.rot_x= link.rot_y= link.rot_z= pointer(0);
link.proj_x= link.proj_y= pointer(0);
link.adj_z= pointer(0);
return &link;
}
func show_list3d
{
link= list3d_head.next;
while(link) {
if(link->is_quad) {
xx= *(link->map_x);
yy= *(link->map_y);
zz= *(link->adj_z);
colr= *(link->colr);
num= numberof( xx(,1) );
if(link->one_colr) {
quad_strip_1c, num, xx(,1), xx(,2), yy(,1), yy(,2),
zz(,1), zz(,2), colr;
} else {
quad_strip_1c, num, xx(,1), xx(,2), yy(,1), yy(,2),
zz(,1), zz(,2), colr(,1), colr(,2);
}
} else {
num= numberof( *(link->map_x) );
if(link->one_colr) {
tri_strip_1c, num, *(link->map_x), *(link->map_y),
*(link->adj_z), *(link->colr);
} else {
tri_strip, num, *(link->map_x), *(link->map_y),
*(link->adj_z), *(link->colr);
}
}
link= link->next;
}
show_zbuf;
}
func remov_link3d(link)
{
if(typeof(link) != "struct_instance") {
error,"remov_link called with a bad argument, must be a link3d struct";
}
#if 0
if(structof(link) != "link3d") {
error,"remov_link called with a bad argument, must be a link3d struct";
}
#endif
if(link.next) (link.next)->prev= link.prev;
if(link.prev) (link.prev)->next= link.next;
}
func clear_list3d(dlist)
{
while(list3d_head.next) {
remov_link3d(*(list3d_head.next));
}
}
func rot_list3d
{
link= list3d_head.next;
while(link) {
xx= *(link->data_x);
yy= *(link->data_y);
zz= *(link->data_z);
do_rotn, xx, yy, zz;
link->rot_x= &xx;
link->rot_y= &yy;
link->rot_z= &zz;
link= link->next;
}
}
func lims_list3d(head)
{
link= head.next;
xlo= ylo= zlo= 1.0e200;
xhi= yhi= zhi= -1.0e200;
while(link) {
xlo= min(xlo, min( *(link->rot_x) ) );
xhi= max(xhi, max( *(link->rot_x) ) );
ylo= min(ylo, min( *(link->rot_y) ) );
yhi= max(yhi, max( *(link->rot_y) ) );
zlo= min(zlo, min( *(link->rot_z) ) );
zhi= max(zhi, max( *(link->rot_z) ) );
link= link->next;
}
res= array(0.0, 3, 2);
res(1,1)= xlo;
res(2,1)= ylo;
res(3,1)= zlo;
res(1,2)= xhi;
res(2,2)= yhi;
res(3,2)= zhi;
return res;
}
func adj_z_list3d
{
link= list3d_head.next;
while(link) {
zz= *(link->rot_z);
adj_zvals, zz;
link->adj_z= &zz;
link= link->next;
}
}
func proj_list3d
{
link= list3d_head.next;
while(link) {
xx= *(link->rot_x);
yy= *(link->rot_y);
project, xx, yy, *(link->adj_z);
link->proj_x= &xx;
link->proj_y= &yy;
link= link->next;
}
}
func set_map_from_list3d
{
extern zbuf_x_off, zbuf_y_off, zbuf_x_scale, zbuf_y_scale;
/* compute the transformation between projected 3D viewpoint coords
and z-buffer coords */
link= list3d_head.next;
xlo= ylo= 1.0e200;
xhi= yhi= -1.0e200;
while(link) {
xx= *(link->proj_x);
yy= *(link->proj_y);
xlo= min(xlo, min(xx));
xhi= max(xhi, max(xx));
ylo= min(ylo, min(yy));
yhi= max(yhi, max(yy));
link= link->next;
}
zbuf_x_off= xlo;
zbuf_y_off= ylo;
zbuf_x_scale= nx_zbuf_terp/(xhi-zbuf_x_off);
zbuf_y_scale= nx_zbuf_terp/(yhi-zbuf_y_off);
}
func map_list3d
{
link= list3d_head.next;
while(link) {
xx= *(link->proj_x);
yy= *(link->proj_y);
map_to_scrn, xx, yy;
link->map_x= &xx;
link->map_y= &yy;
link= link->next;
}
}
func clr_zbuf
/* DOCUMENT clr_zbuf()
Clears the z-buffer and sets all pixels to color zero.
SEE ALSO: init_zbuf
*/
{
extern zbuf_terp;
extern pixbuf_terp;
zbuf_terp(..)= -1.0e100;
pixbuf_terp(..)= char(0);
}
func init_zbuf(nx, ny)
/* DOCUMENT init_zbuf()
Creates the z-buffer (if needed) and the 3D display list.
SEE ALSO: clr_zbuf
*/
{
extern zbuf_terp, pixbuf_terp;
extern nx_zbuf_terp, ny_zbuf_terp;
extern list3d_head;
if(nx < 4 || ny < 4 || nx > 4096 || ny > 4096) {
error,"init_zbuf(), nx or ny is out of range";
}
if(is_void(list3d_head)) {
list3d_head= array(link3d);
list3d_head.data_x= list3d_head.data_y= list3d_head.data_z= pointer(0);
list3d_head.rot_x= list3d_head.rot_y= list3d_head.rot_z= pointer(0);
list3d_head.proj_x= list3d_head.proj_y= pointer(0);
list3d_head.adj_z= pointer(0);
list3d_head.one_colr= 0;
list3d_head.is_quad= 0;
}
/* make new z-buffer only if sizes have changed */
if(nx != nx_zbuf_terp || ny != ny_zbuf_terp) {
nx_zbuf_terp= nx;
ny_zbuf_terp= ny;
zbuf_terp= array(0.0, nx, ny);
pixbuf_terp= array(char(0), nx, ny);
clr_zbuf;
_make_zbuf, nx, ny, zbuf_terp, pixbuf_terp;
}
}
func show_zbuf
/* DOCUMENT show_zbuf()
Display the z-buffered image.
SEE ALSO: clr_zbuf
*/
{
extern pixbuf_terp;
/* Use a cell array to show the z-buffered image, and set the
limits to show the active portion of the viewplane. */
pli,pixbuf_terp,view_box(1,1),view_box(2,1),view_box(1,2),view_box(2,2);
}
func project(&x, &y, z)
/* DOCUMENT project(x, y, z)
Project the x and y coords onto the projection plane.
x, y, and z must already be in viewpoint coords.
Modifies the x and y inputs.
SEE ALSO: do_rotn, adj_zvals, do_trans
*/
{
if(no_project) return;
/* perform perspective projection of the vectors x, y, z */
if(numberof(x) != numberof(y) || numberof(x) != numberof(z)) {
error,"vectors of different length passed to project()";
}
x= (x-x_viewpoint)*z_viewdist/z;
y= (y-y_viewpoint)*z_viewdist/z;
}
func set_viewdist(vdist)
/* DOCUMENT set_viewdist(view_dist)
Sets the distance between the viewer and the origin in
world coords. as measured along the viewing direction.
SEE ALSO: set_viewpoint
*/
{
view_dist= vdist;
use_viewpoint= 0;
}
func set_viewpoint(view_loc)
/* DOCUMENT set_viewpoint(view_loc)
Sets the point where the viewer is located in world coords.
SEE ALSO: set_viewdist
*/
{
extern view_world;
view_world= view_loc;
use_viewpoint= 1;
}
func adj_zvals(&z)
/* DOCUMENT adj_zvals(z)
Apply the z-offset part of the viewpoint transform
to z. Modifies z.
SEE ALSO: do_rotn, do_trans, project
*/
{
extern z_viewpoint;
/* adjust so viewer is at z=0 */
z -= z_viewpoint;
if(max(z) >= 0.0) "Warning: at least one point is behind viewpoint";
}
func do_rotn(&x, &y, &z)
/* DOCUMENT do_rotn(x, y, z)
Apply the rotation part of the viewpoint transform
to x, y, and z. Modifies all three args.
SEE ALSO: do_trans, adj_zvals, project
*/
{
extern trans_vec1, trans_vec2, trans_vec3;
if(numberof(x) != numberof(y) || numberof(x) != numberof(z)) {
error,"vectors of different length passed to do_rotn()";
}
xp= trans_vec1(1)*x+trans_vec1(2)*y+trans_vec1(3)*z;
yp= trans_vec2(1)*x+trans_vec2(2)*y+trans_vec2(3)*z;
zp= trans_vec3(1)*x+trans_vec3(2)*y+trans_vec3(3)*z;
x= xp;
y= yp;
z= zp;
}
func set_rotn(theta, phi, psi)
/* DOCUMENT set_rotn(theta, phi, psi)
theta and phi specify the viewing direction in
world coords, and are the direction headed toward the viewer.
psi is the rotation about the viewing direction and is used
to get the expected "up" direction.
SEE ALSO: set_viewpoint, set_trans
*/
{
extern trans_vec1, trans_vec2, trans_vec3;
/* compute the transformation between world coords and
the 3D viewpoint coords */
snth= sin(theta);
csth= cos(theta);
snph= sin(phi);
csph= cos(phi);
snpsi= sin(psi);
cspsi= cos(psi);
trans_vec1= [-csth*csph*snpsi-snph*cspsi, -csth*snph*snpsi+csph*cspsi,
snth*snpsi];
trans_vec2= [-csth*csph*cspsi+snph*snpsi, -csth*snph*cspsi-csph*snpsi,
snth*cspsi];
trans_vec3= [snth*csph, snth*snph, csth];
}
func do_trans(&x, &y, &z)
/* DOCUMENT do_trans(x, y, z)
Transform x, y, and z to viewpoint coords.
Modifies all three args.
SEE ALSO: do_rotn, adj_zvals, project
*/
{
do_rotn,x,y,z;
adj_zvals,z;
}
func set_trans(theta, phi, psi)
/* DOCUMENT set_trans(theta, phi, psi)
theta and phi specify the viewing direction in
world coords, and are the direction headed toward the viewer.
psi is the rotation about the viewing direction and is used
to get the expected "up" direction.
The viewpoint must have been set in world coords (or specified
as a distance from the origin) earlier, but it is
mapped to viewpoint coords here.
SEE ALSO: set_viewpoint, set_viewdist, set_rotn
*/
{
extern x_viewpoint, y_viewpoint, z_viewpoint, view_world, view_dist, use_viewpoint;
set_rotn, theta, phi, psi;
/* Transform the viewpoint from world coords to viewpoint coords.
Anything with a z greater than the resulting z_viewpoint cannot be seen */
if(use_viewpoint) {
x_viewpoint= trans_vec1(1)*view_world(1)+trans_vec1(2)*view_world(2)+
trans_vec1(3)*view_world(3);
y_viewpoint= trans_vec2(1)*view_world(1)+trans_vec2(2)*view_world(2)+
trans_vec2(3)*view_world(3);
z_viewpoint= trans_vec3(1)*view_world(1)+trans_vec3(2)*view_world(2)+
trans_vec3(3)*view_world(3);
} else {
x_viewpoint= 0.0;
y_viewpoint= 0.0;
z_viewpoint= view_dist;
}
}
func map_to_scrn(&x, &y)
{
extern zbuf_x_scale, zbuf_y_scale, view_box;
/* NOTE: no clipping here */
x= (x-view_box(1,1))*zbuf_x_scale+1.0;
y= (y-view_box(2,1))*zbuf_y_scale+1.0;
}
func pick_viewbox_link3d
/* DOCUMENT pick_viewbox_link3d
Automatically pick the viewing area on the view plane when
using a 3D display list.
SEE ALSO: free_viewbox, set_viewbox, map_to_scrn
*/
{
extern view_box;
lims= lims_list3d(list3d_head);
/* Set the viewing area to 10% bigger than the range of the objects.
*/
delx= lims(1,2)-lims(1,1);
dely= lims(2,2)-lims(2,1);
view_box= lims(1:2,1:2);
view_box(1,1) -= 0.05*delx;
view_box(1,2) += 0.05*delx;
view_box(2,1) -= 0.05*delx;
view_box(2,2) += 0.05*delx;
zbuf_x_scale= (nx_zbuf_terp-1.0)/(view_box(1,2)-view_box(1,1));
zbuf_y_scale= (ny_zbuf_terp-1.0)/(view_box(2,2)-view_box(2,1));
}
func pick_viewbox(xvals, yvals)
/* DOCUMENT pick_viewbox(xvals, yvals)
Automatically choose a mapping between viewing plane coords
and coords in the pixel buffer based on the x and y inputs.
SEE ALSO: free_viewbox, set_viewbox, map_to_scrn
*/
{
extern zbuf_x_scale, zbuf_y_scale, fixed_map, view_box;
/* do not perform if the user has set a "fixed" mapping */
if(fixed_map) return;
/* compute the transformation between projected 3D viewpoint coords
and z-buffer coords */
view_box(1,1)= min(xvals);
view_box(1,2)= max(xvals);
view_box(2,1)= min(yvals);
view_box(2,2)= max(yvals);
zbuf_x_scale= (nx_zbuf_terp-1.0)/(view_box(1,2)-view_box(1,1));
zbuf_y_scale= (ny_zbuf_terp-1.0)/(view_box(2,2)-view_box(2,1));
}
func set_viewbox(xlo, xhi, ylo, yhi)
/* DOCUMENT set_viewbox(xlo, xhi, ylo, yhi)
Specify the range in x and y, in the viewing plane,
to map to the pixel buffer.
SEE ALSO: free_viewbox, pick_viewbox, map_to_scrn
*/
{
extern zbuf_x_scale, zbuf_y_scale, fixed_map, view_box;
/* hold the mapping between viewing plane coords and screen
coords fixed as chosen by the user */
fixed_map= 1;
/* compute the transformation between projected 3D viewpoint coords
and z-buffer coords */
view_box(1,1)= xlo;
view_box(1,2)= xhi;
view_box(2,1)= ylo;
view_box(2,2)= yhi;
zbuf_x_scale= (nx_zbuf_terp-1.0)/(view_box(1,2)-view_box(1,1));
zbuf_y_scale= (ny_zbuf_terp-1.0)/(view_box(2,2)-view_box(2,1));
}
func free_viewbox
/* DOCUMENT free_viewbox
The mapping between viewing plane coords and coords in
the pixel buffer will be set automatically.
SEE ALSO: pick_viewbox, set_viewbox, map_to_scrn
*/
{
extern fixed_map;
/* should automatically pick the mapping between viewing plane
coords and screen coords */
fixed_map= 0;
}
/* create an initial z-buffer and pixmap */
if(numberof(zbuf_terp) < 16) {
nx_zbuf_terp= 0;
ny_zbuf_terp= 0;
}
init_zbuf, 64, 64;
free_viewbox;
set_viewpoint, [0.0, 0.0, 100.0];
set_trans, pi/4.0, 0.0, pi/2.0;